/*
 * Copyright (C) 2010 ZXing authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.yksj.healthtalk.camera;

import java.util.Collection;
import java.util.regex.Pattern;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Point;
import android.hardware.Camera;
import android.os.Build;
import android.util.Log;
import android.view.Display;
import android.view.WindowManager;

final class CameraConfigurationManager {

	  private static final String TAG = CameraConfigurationManager.class.getSimpleName();

	  private static final int TEN_DESIRED_ZOOM = 27;
	  private static final int DESIRED_SHARPNESS = 30;

	  private static final Pattern COMMA_PATTERN = Pattern.compile(",");

	  private final Context context;
	  private Point screenResolution;
	  private Point cameraResolution;
	  private int previewFormat;
	  private String previewFormatString;

	  CameraConfigurationManager(Context context) {
	    this.context = context;
	  }

	  /**
	   * Reads, one time, values from the camera that are needed by the app.
	   */
	  void initFromCameraParameters(Camera camera) {
	    Camera.Parameters parameters = camera.getParameters();
	    previewFormat = parameters.getPreviewFormat();
	    previewFormatString = parameters.get("preview-format");
	    Log.d(TAG, "Default preview format: " + previewFormat + '/' + previewFormatString);
	    WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
	    Display display = manager.getDefaultDisplay();
	    screenResolution = new Point(display.getWidth(), display.getHeight());
	    Log.d(TAG, "Screen resolution: " + screenResolution);
	    cameraResolution = getCameraResolution(parameters, screenResolution);
	    Log.d(TAG, "Camera resolution: " + screenResolution);
	    /**
	     * 因为方向转成竖直后Screen与Camera关系仍然按照横向比例缩放，导致扭曲。
	     * 新建一个Point把screenResolution获取的屏幕分辨率x，y值颠倒一下，替换掉。
	     */
	    cameraResolution = screenResolution;
	   	Point screenResolutionForCamera = new Point();
	   	screenResolutionForCamera.x = cameraResolution.x;
	   	screenResolutionForCamera.y = cameraResolution.y;
	   	// preview size is always something like 480*320, other 320*480
	   	if (cameraResolution.x < cameraResolution.y) {
	   		screenResolutionForCamera.x = cameraResolution.y;
	   		screenResolutionForCamera.y = cameraResolution.x;
	   	}
	   	cameraResolution = getCameraResolution(parameters, screenResolutionForCamera);
	  }

	  /**
	   * Sets the camera up to take preview images which are used for both preview and decoding.
	   * We detect the preview format here so that buildLuminanceSource() can build an appropriate
	   * LuminanceSource subclass. In the future we may want to force YUV420SP as it's the smallest,
	   * and the planar Y can be used for barcode scanning without a copy in some cases.
	   */
	  @SuppressLint("NewApi")
	void setDesiredCameraParameters(Camera camera) {
	    Camera.Parameters parameters = camera.getParameters();
	    Log.d(TAG, "Setting preview size: " + cameraResolution);
	    parameters.setPreviewSize(cameraResolution.x, cameraResolution.y);
	    camera.setDisplayOrientation(90); 
	    setFlash(parameters);
	    setZoom(parameters);
	    //setSharpness(parameters);
	    camera.setParameters(parameters);
	  }

	  Point getCameraResolution() {
	    return cameraResolution;
	  }

	  Point getScreenResolution() {
	    return screenResolution;
	  }

	  int getPreviewFormat() {
	    return previewFormat;
	  }

	  String getPreviewFormatString() {
	    return previewFormatString;
	  }

	  private static Point getCameraResolution(Camera.Parameters parameters, Point screenResolution) {

	    String previewSizeValueString = parameters.get("preview-size-values");
	    // saw this on Xperia
	    if (previewSizeValueString == null) {
	      previewSizeValueString = parameters.get("preview-size-value");
	    }

	    Point cameraResolution = null;

	    if (previewSizeValueString != null) {
	      Log.d(TAG, "preview-size-values parameter: " + previewSizeValueString);
	      cameraResolution = findBestPreviewSizeValue(previewSizeValueString, screenResolution);
	    }

	    if (cameraResolution == null) {
	      // Ensure that the camera resolution is a multiple of 8, as the screen may not be.
	      cameraResolution = new Point(
	          (screenResolution.x >> 3) << 3,
	          (screenResolution.y >> 3) << 3);
	    }

	    return cameraResolution;
	  }

	  private static Point findBestPreviewSizeValue(CharSequence previewSizeValueString, Point screenResolution) {
	    int bestX = 0;
	    int bestY = 0;
	    int diff = Integer.MAX_VALUE;
	    for (String previewSize : COMMA_PATTERN.split(previewSizeValueString)) {

	      previewSize = previewSize.trim();
	      int dimPosition = previewSize.indexOf('x');
	      if (dimPosition < 0) {
	        Log.w(TAG, "Bad preview-size: " + previewSize);
	        continue;
	      }

	      int newX;
	      int newY;
	      try {
	        newX = Integer.parseInt(previewSize.substring(0, dimPosition));
	        newY = Integer.parseInt(previewSize.substring(dimPosition + 1));
	      } catch (NumberFormatException nfe) {
	        Log.w(TAG, "Bad preview-size: " + previewSize);
	        continue;
	      }

	      int newDiff = Math.abs(newX - screenResolution.x) + Math.abs(newY - screenResolution.y);
	      if (newDiff == 0) {
	        bestX = newX;
	        bestY = newY;
	        break;
	      } else if (newDiff < diff) {
	        bestX = newX;
	        bestY = newY;
	        diff = newDiff;
	      }

	    }

	    if (bestX > 0 && bestY > 0) {
	      return new Point(bestX, bestY);
	    }
	    return null;
	  }

	  private static int findBestMotZoomValue(CharSequence stringValues, int tenDesiredZoom) {
	    int tenBestValue = 0;
	    for (String stringValue : COMMA_PATTERN.split(stringValues)) {
	      stringValue = stringValue.trim();
	      double value;
	      try {
	        value = Double.parseDouble(stringValue);
	      } catch (NumberFormatException nfe) {
	        return tenDesiredZoom;
	      }
	      int tenValue = (int) (10.0 * value);
	      if (Math.abs(tenDesiredZoom - value) < Math.abs(tenDesiredZoom - tenBestValue)) {
	        tenBestValue = tenValue;
	      }
	    }
	    return tenBestValue;
	  }

	  /**
		* @Title: getFlashMode 
		* @Description: 获取闪光灯模式
		* @param @param parameters 
		* @param @param start true为开,false为关
		* @param @return 支持返回模式,不支持返回空
		 */
		public String getFlashMode(Camera.Parameters parameters, boolean start) {
			String flashMode;
			if (start) {
				//设置闪光灯
				flashMode = findSettableValue(parameters.getSupportedFlashModes(), Camera.Parameters.FLASH_MODE_TORCH,
						Camera.Parameters.FLASH_MODE_ON);
			} else {
				flashMode = findSettableValue(parameters.getSupportedFlashModes(), Camera.Parameters.FLASH_MODE_OFF);
			}
			return flashMode;
		}
		
		private String findSettableValue(Collection<String> supportedValues, String... desiredValues) {
			String result = null;
			if (supportedValues != null) {
				for (String desiredValue : desiredValues) {
					if (supportedValues.contains(desiredValue)) {
						result = desiredValue;
						break;
					}
				}
			}
			return result;
		}
	  
	  private void setFlash(Camera.Parameters parameters) {
	    // FIXME: This is a hack to turn the flash off on the Samsung Galaxy.
	    // And this is a hack-hack to work around a different value on the Behold II
	    // Restrict Behold II check to Cupcake, per Samsung's advice
	    //if (Build.MODEL.contains("Behold II") &&
	    //    CameraManager.SDK_INT == Build.VERSION_CODES.CUPCAKE) {
	    if (Build.MODEL.contains("Behold II") && CameraManager.SDK_INT == 3) { // 3 = Cupcake
	      parameters.set("flash-value", 1);
	    } else {
	      parameters.set("flash-value", 2);
	    }
	    // This is the standard setting to turn the flash off that all devices should honor.
	    parameters.set("flash-mode", "off");
	  }

	  private void setZoom(Camera.Parameters parameters) {

	    String zoomSupportedString = parameters.get("zoom-supported");
	    if (zoomSupportedString != null && !Boolean.parseBoolean(zoomSupportedString)) {
	      return;
	    }

	    int tenDesiredZoom = TEN_DESIRED_ZOOM;

	    String maxZoomString = parameters.get("max-zoom");
	    if (maxZoomString != null) {
	      try {
	        int tenMaxZoom = (int) (10.0 * Double.parseDouble(maxZoomString));
	        if (tenDesiredZoom > tenMaxZoom) {
	          tenDesiredZoom = tenMaxZoom;
	        }
	      } catch (NumberFormatException nfe) {
	        Log.w(TAG, "Bad max-zoom: " + maxZoomString);
	      }
	    }

	    String takingPictureZoomMaxString = parameters.get("taking-picture-zoom-max");
	    if (takingPictureZoomMaxString != null) {
	      try {
	        int tenMaxZoom = Integer.parseInt(takingPictureZoomMaxString);
	        if (tenDesiredZoom > tenMaxZoom) {
	          tenDesiredZoom = tenMaxZoom;
	        }
	      } catch (NumberFormatException nfe) {
	        Log.w(TAG, "Bad taking-picture-zoom-max: " + takingPictureZoomMaxString);
	      }
	    }

	    String motZoomValuesString = parameters.get("mot-zoom-values");
	    if (motZoomValuesString != null) {
	      tenDesiredZoom = findBestMotZoomValue(motZoomValuesString, tenDesiredZoom);
	    }

	    String motZoomStepString = parameters.get("mot-zoom-step");
	    if (motZoomStepString != null) {
	      try {
	        double motZoomStep = Double.parseDouble(motZoomStepString.trim());
	        int tenZoomStep = (int) (10.0 * motZoomStep);
	        if (tenZoomStep > 1) {
	          tenDesiredZoom -= tenDesiredZoom % tenZoomStep;
	        }
	      } catch (NumberFormatException nfe) {
	        // continue
	      }
	    }

	    // Set zoom. This helps encourage the user to pull back.
	    // Some devices like the Behold have a zoom parameter
	    if (maxZoomString != null || motZoomValuesString != null) {
	      parameters.set("zoom", String.valueOf(tenDesiredZoom / 10.0));
	    }

	    // Most devices, like the Hero, appear to expose this zoom parameter.
	    // It takes on values like "27" which appears to mean 2.7x zoom
	    if (takingPictureZoomMaxString != null) {
	      parameters.set("taking-picture-zoom", tenDesiredZoom);
	    }
	  }

	  /*
	  private void setSharpness(Camera.Parameters parameters) {

	    int desiredSharpness = DESIRED_SHARPNESS;

	    String maxSharpnessString = parameters.get("sharpness-max");
	    if (maxSharpnessString != null) {
	      try {
	        int maxSharpness = Integer.parseInt(maxSharpnessString);
	        if (desiredSharpness > maxSharpness) {
	          desiredSharpness = maxSharpness;
	        }
	      } catch (NumberFormatException nfe) {
	        Log.w(TAG, "Bad sharpness-max: " + maxSharpnessString);
	      }
	    }

	    parameters.set("sharpness", desiredSharpness);
	  }
	   */
	}

